/*
    InfoBar.js
    Copyright (C) 2010, Donald W. Griffin
    All Rights Reserved
*/
Ext.namespace("Wdg");

// See:
//  http://www.sencha.com/forum/showthread.php?59479
//  http://www.sencha.com/forum/showthread.php?46395
//  http://www.sencha.com/forum/showthread.php?29250
//  http://www.sencha.com/forum/showthread.php?11825

Wdg.ToolbarMgr = Ext.extendX(Object, function (base) {
    function beginResize () { // this is the Toolbar
        this._beforeHeight = this.el.getHeight();
    }

    function endResize () { // this is the Toolbar
        var h = this.el.getHeight(), p = this.ownerPanel, dh = this._beforeHeight - h;

        if (dh) {
            var ph = p.body.getHeight();
            p.body.setHeight(ph + dh);
            p.doLayout();
        }
    }

    function getNextName () {
        var p = this.panel, t = this.toolbar;

        for (var i = 2, s; p[s = t + i]; ++i)
            {}

        return s;
    }

    function watchToolbar (tb) {
        tb.beginResize = beginResize;
        tb.endResize = endResize;

        tb.on({
            beforehide: this.onBeforeShowHideBar,
            beforeshow: this.onBeforeShowHideBar,
            hide: this.onShowHideBar,
            show: this.onShowHideBar,
            scope: this
        })
    }

    return {
        toolbar: "tbar",

        constructor: function (cfg) {
            if (typeof(cfg) === "string") {
                this.toolbar = cfg;
            } else {
                Ext.apply(this, cfg);
            }
        },

        init: function (panel) {
            this.panel = panel;
            panel[this.toolbar + "s"] = {
                add: this.addToolbar.createDelegate(this)
            };

            if (!panel[this.toolbar]) {
                panel.elements += "," + this.toolbar;
            }

            panel.on({
                afterrender: this.onAfterRender,
                single: true,
                scope: this
            })
        },

        addToolbar: function (tbarCfg, name) {
            var tb = Ext.isArray(tbarCfg) ? { xtype: "toolbar", items: tbarCfg } : tbarCfg;

            if (!tb.initComponent) { // if (not a component instance)
                tb = Ext.create(tb);
            }

            if (!name) {
                name = getNextName.call(this);
            }
            this.panel[name] = tb;

            tb.ownerPanel = this.panel;
            watchToolbar.call(this, tb);

            if (this.panel.rendered) {
                tb.render(this.panel[this.toolbar]);
                tb.el.setVisibilityMode(Ext.Element.DISPLAY);
                tb._beforeHeight = 0;
                tb.endResize();
            }

            return tb;
        },

        onAfterRender: function () {
            var p = this.panel, t = this.toolbar;

            var tb = p[t];
            watchToolbar.call(this, tb);

            for (var s, i = 2; (tb = p[s = t + i]); ++i) {
                this.addToolbar(tb, s);
            }
        },

        onBeforeShowHideBar: function (tb) {
            tb.beginResize();
        },

        onShowHideBar: function (tb) {
            tb.endResize();
        }
    };
});

Wdg.InfoBar = Ext.extendX(Ext.BoxComponent, function (base) {
    var levels = { error: 0, warning: 1, info: 2 };

    function findPos (msg) {
        var level = levels[msg.type];

        for (var i = 0, n = this.messages.length; i < n; ++i) {
            var m = this.messages[i], ml = levels[m.type];
            if (level < ml) {
                return i;
            }
        }

        return -1;
    }

    return {
        xtype: "wdg-infobar",
        bubbleEvents: ["valid", "invalid"],
        cls: "wdg-infobar",
        closeTip: "Dismiss all messages",
        moreTip: "Go to next message",
        //height: 0,
        autoHeight: true,
        infoTpl: [
            '<div class="{cls}-inner">',
                '<div class="{cls}-icon {type}-icon"></div>',
                '<div class="{cls}-text">{message}</div>',
                '<div class="{cls}-icon wdg-close-icon" qtip="{closeTip}"></div>',
                '<div style="clear:both;"></div>',
                '<tpl if="more">',
                '<a class="{cls}-more" href="javascript:void(0)" qtip="{moreTip}">({more} more)</a>',
                '</tpl>',
                '<div style="clear:both;"></div>',
            '</div>'
        ].join(""),

        initComponent: function () {
            base.initComponent.call(this);

            this.messages = [];
            if (typeof(this.infoTpl) === "string") {
                this.infoTpl = new Ext.XTemplate(this.infoTpl);
            }

            this.addEvents(
                "invalid",
                "valid"
            );
            this.enableBubble(this.bubbleEvents);
        },

        addError: function (msg) {
            this.addMessage(msg, "error");
        },

        addInfo: function (msg) {
            this.addMessage(msg, "info");
        },

        addWarning : function (msg) {
            this.addMessage(msg, "warning");
        },

        addMessage: function (msg, type) {
            var obj = (typeof(msg) === "string") ? { message: msg } : msg;
            obj.type = obj.type || type || "info";

            var pos = findPos.call(this, obj);
            if (pos < 0) {
                this.messages.push(obj);
            } else {
                this.messages.splice(pos, 0, obj);
            }

            this.updateDisplay();
        },

        afterRender: function () {
            base.afterRender.call(this);
            this.mon(this.el, "click", this.onClick, this);
            //this.addError.defer(10, this, ["Hey man"]);
        },

        getActiveError: function () {
            if (this.messages.length) {
                var m = this.messages[0];
                if (m.type === "error") {
                    return m.message;
                }
            }

            return ""; // this is what Ext returns for no error...
        },

        getBubbleTarget: function () {
            return this.ownerPanel;
        },

        onClick: function (e) {
            var t = e.getTarget();

            if (Ext.fly(t).hasClass(this.cls+"-more")) {
                this.messages.shift();
            } else if (Ext.fly(t).hasClass("wdg-close-icon")) {
                this.messages = [];
            } else {
                return;
            }

            this.updateDisplay();
        },

        onResize : function(adjWidth, adjHeight, rawWidth, rawHeight) {
            base.onResize.apply(this, arguments);
            this.updateDisplay();
        },

        updateDisplay: function (anim) {
            if (!this.rendered)
                return;

            var vis = this.isVisible();

            if (this.messages.length) {
                var msg = this.messages[0];
                var obj = Ext.apply({
                    cls: this.cls,
                    closeTip: this.closeTip,
                    moreTip: this.moreTip,
                    total: this.messages.length,
                    more: this.messages.length - 1
                }, msg);

                if (vis) {
                    this.beginResize();
                }

                var html = this.infoTpl.apply(obj);
                this.el.dom.innerHTML = html;

                if (vis) {
                    this.endResize();
                } else {
                    this.show();
                }
            }
            else if (vis) {
                this.hide();
            }

            var err = this.getActiveError(), valid = !err;
            if (valid !== this.wasValid) {
                this.wasValid = valid;
                if (valid) {
                    this.fireEvent("valid", this);
                } else {
                    this.fireEvent("invalid", this, err);
                }
            }
        }
    };
});

Ext.reg(Wdg.InfoBar.prototype.xtype, Wdg.InfoBar);
